03 函数
写了重复的代码?把它抽成函数。逻辑太长看不清?把它拆成函数。函数是组织代码的基本方式,Python的函数定义简单,但参数机制很灵活。
一、定义函数
1.1 基本语法
用def定义函数:
python
>>> def fib(n):
... """输出小于n的斐波那契数列"""
... a, b = 0, 1
... while a < n:
... print(a, end=' ')
... a, b = b, a+b
... print()
...
>>> fib(2000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597def后面跟函数名和参数列表,冒号开头,缩进的是函数体。第一行字符串是文档字符串(docstring),用help()时会显示。
1.2 return语句
python
>>> def fib_list(n):
... """返回小于n的斐波那契数列"""
... result = []
... a, b = 0, 1
... while a < n:
... result.append(a)
... a, b = b, a+b
... return result
...
>>> fib_list(100)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]没有return语句,或者return后面没有值,函数返回None。
二、默认参数
2.1 基本用法
python
>>> def ask_ok(prompt, retries=4, reminder='请重试!'):
... while True:
... reply = input(prompt)
... if reply in ('y', 'ye', 'yes'):
... return True
... if reply in ('n', 'no', 'nop', 'nope'):
... return False
... retries -= 1
... if retries < 0:
... raise ValueError('无效的用户响应')
... print(reminder)调用方式:
python
ask_ok('确定吗?') # 只传必填参数
ask_ok('确定吗?', 2) # 重试2次
ask_ok('确定吗?', 2, '再来一次!') # 全部指定2.2 默认值只计算一次
python
>>> def f(a, L=[]):
... L.append(a)
... return L
...
>>> print(f(1))
[1]
>>> print(f(2))
[1, 2]
>>> print(f(3))
[1, 2, 3]默认值在def时计算一次,之后每次调用共享同一个对象。如果默认值是可变对象(列表、字典等),就会出现上面的意外行为。
2.3 避免可变默认值陷阱
python
>>> def f(a, L=None):
... if L is None:
... L = []
... L.append(a)
... return L
...
>>> print(f(1))
[1]
>>> print(f(2))
[2]用None作为默认值,函数体内再判断,就不会有共享问题了。
三、关键字参数
3.1 基本用法
python
>>> def parrot(voltage, state='a stiff', action='voom'):
... print(f"这只鹦鹉 {action}")
... print(f"电压: {voltage}")
... print(f"状态: {state}")
...
>>> parrot(1000)
这只鹦鹉 voom
电压: 1000
状态: a stiff
>>> parrot(voltage=1000000, action='VOOOOOM')
这只鹦鹉 VOOOOOM
电压: 1000000
状态: a stiff
>>> parrot('a million', 'bereft of life', 'jump')
这只鹦鹉 jump
电压: a million
状态: bereft of life关键字参数必须在位置参数后面。
3.2 *args和**kwargs
python
>>> def cheeseshop(kind, *args, **kwargs):
... print(f"奶酪: {kind}")
... print(f"位置参数: {args}")
... print(f"关键字参数: {kwargs}")
...
>>> cheeseshop("Brie", "one", "two", shop="cheese shop", client="Mr. Cheese")
奶酪: Brie
位置参数: ('one', 'two')
关键字参数: {'shop': 'cheese shop', 'client': 'Mr. Cheese'}*args收集多余的位置参数为元组,**kwargs收集多余的关键字参数为字典。
四、特殊参数
4.1 仅限位置参数
在/前面的参数只能用位置传入:
python
>>> def standard_arg(arg1, arg2=None):
... print(arg1, arg2)
...
>>> standard_arg(1, 2) # OK
>>> standard_arg(arg1=1) # OK
>>> def pos_only_arg(arg1, arg2=None, /):
... print(arg1, arg2)
...
>>> pos_only_arg(1, 2) # OK
>>> pos_only_arg(arg1=1) # 报错!arg1是仅限位置参数4.2 仅限关键字参数
在*后面的参数只能用关键字传入:
python
>>> def kwd_only_arg(*, arg1, arg2=None):
... print(arg1, arg2)
...
>>> kwd_only_arg(arg1=1) # OK
>>> kwd_only_arg(1) # 报错!arg1是仅限关键字参数4.3 组合使用
python
>>> def combined(pos_only, /, standard, *, kwd_only):
... print(pos_only, standard, kwd_only)
...
>>> combined(1, 2, kwd_only=3) # OK
>>> combined(1, standard=2, kwd_only=3) # OK
>>> combined(pos_only=1, standard=2, kwd_only=3) # 报错五、lambda表达式
5.1 基本用法
lambda创建匿名小函数:
python
>>> def make_incrementor(n):
... return lambda x: x + n
...
>>> f = make_incrementor(42)
>>> f(0)
42
>>> f(1)
435.2 配合排序
python
>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
>>> pairs.sort(key=lambda pair: pair[1])
>>> pairs
[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]lambda只能有一个表达式,不能有语句、注释或复杂逻辑。需要复杂逻辑就用def。
六、文档字符串
6.1 写法约定
python
>>> def my_function():
... """这里写函数的简短说明。
...
... 这里写更详细的说明,可以写多行。
... 说明函数的功能、参数、返回值等。
... """
... pass
...
>>> help(my_function)第一行简短说明,空一行后写详细说明。help()函数会显示文档字符串。
6.2 类的文档字符串
python
class MyClass:
"""类的简短说明。
详细说明写在这里。
"""
def my_method(self):
"""方法的简短说明。"""
pass七、函数注解(3.0+)
7.1 基本注解
python
>>> def f(ham: str, eggs: str = 'eggs') -> str:
... print("Annotations:", f.__annotations__)
... print("Arguments:", ham, eggs)
... return ham + ' and ' + eggs
...
>>> f('spam')
Annotations: {'ham': <class 'str'>, 'eggs': <class 'str'>, 'return': <class 'str'>}
Arguments: spam eggs
'spam and eggs'注解是可选的元信息,不影响运行,但可以被IDE和类型检查工具使用。
八、总结
| 特性 | 说明 |
|---|---|
def | 定义函数 |
return | 返回值,没有则返回None |
| 默认参数 | def f(a, b=1) |
*args | 收集位置参数为元组 |
**kwargs | 收集关键字参数为字典 |
/ | 前面的参数仅限位置 |
* | 后面的参数仅限关键字 |
lambda | 匿名小函数 |
| 文档字符串 | 函数第一行字符串 |
| 注解 | def f(a: int) -> str |
默认参数只计算一次,避免用可变对象(列表、字典)做默认值。lambda适合简单表达式,复杂逻辑用def。